// 2025/4/21: 首个版本
// 2025/4/30: 添加注释

var ImageLabelClass = {
    Unknown: 0, // 未知

    Auto: 100, // General automobile / 机动车大类
    Car: 101, // 轿车
    Bus: 102, //大巴
    Midibus: 103, // 小巴
    Truck: 104, // 货车
    Van: 105, // 面包车
    Semitrailer: 106, // 货柜车
    Trailer: 107, // 拖车
    SUV: 108, // SUV
    TinyCar: 109, // 微型车

    Minor: 200, // General vulnerable road user / 弱势参与者大类
    Ped: 201, // Pedestrian / 行人
    Bicycle: 202, // 自行车
    Tricycle: 203, // 三轮车
    Motorbike: 204, // 摩托车
    Wheelchair: 205, // 轮椅
    Animal: 206, // 动物

    Static: 300, // General static object / 静态目标大类
    ZebraCrossing: 301, // 斑马线
    TrafficLight: 302, // 交通灯
    TrafficSign: 303, // 交通信号
    ParkingSlot: 304, // 车位
    Cone: 305, // 锥形路障
    ManholeCover: 306, // 井盖
    Patch: 307, // 路面补丁
    Gantry: 308, // 龙门架
    Pole: 309, // 竖杆
    Tree: 310, // 树木
    Vegetation: 311, // 灌木
    Building: 312, // 建筑物

    Dashboard: 1000, // Dashboard signal / 仪表盘标识大类
    Airbag: 1001, // 安全气囊
    ABS: 1002, // 防抱死制动
    BrakeSystemFailure: 1003, // 刹车系统故障
    ChargingSystemFailure: 1004, // 充电系统故障
    CentralWarningLamp: 1005, // 中央警告灯
    CoolingSystemFailure: 1006, // 冷却系统故障
    DoorsOpen: 1007, // 车门未关
    ElectronicPowerSteering: 1008, // 转向助力
    ElectronicStability: 1009, // 电子稳定性(ESC)
    EnginePreheating: 1010, // 发动机预热
    FrontFogLight: 1011, // 前雾灯
    LaneDepartureWarning: 1012, // 车道偏离预警
    LowBeam: 1013, // 近光灯
    LowEngineOilWarning: 1014, // 低燃油警告
    SeatBelt: 1015, // 安全带提醒
    SideLamp: 1016, // 示廓灯
    TyrePressureMonitoring: 1017, // 胎压异常
    WasherFluid: 1018, // 玻璃水不足
};

function ImageLabelRect(left, top, width, height) {
    this.left = left; // [pix] Left coordinate of the rectangle / 矩形框左边界
    this.top = top; // [pix] Top coordinate of the rectangle / 矩形框上边界
    this.width = width; // [pix] Width of the rectangle / 矩形框宽度
    this.height = height; // [pix] Height of the rectangle / 矩形框高度
}

function ImageLabel() {
    this.id = 0; // 标签ID
    this.class = ImageLabelClass.Unknown; // 标签类型
    this.classConfidence = null; // [%] Classification confidence / 分类置信度
    this.distance = null; // [m] Average distance between the label's pixels to the camera (along x axis of camera coordinate system) / 标签距摄像头的平均距离（沿摄像头x轴方向）
    this.rect = null; // [pix] Border of the label / 标签矩形框 (ImageLabelRect)
    this.description = null; // 描述信息
}

function ImageLabelSample(session, time) {
    this.session = session; // Date or AppoxSessionIdentifier
    this.time = time; // [s] Time offset in session / Session内的相对时间
    this.imageSize = null; // [pix] 图像尺寸 (BISize)
    this.labels = []; // List of labels / 标签列表
}

function convImageLabelSampleV1(gs) {
    if (gs.values.length < 4) return null;
    if (gs.values[0] == null || gs.values[0] != gs.channel) return null;
    if (gs.values[1] == null || gs.values[2] == null || gs.values[3] == null) return null;

    var width = gs.values[1];
    var height = gs.values[2];
    var labelCount = gs.values[3];
    if (gs.values.length != 4 + labelCount * 7) return null;

    var sample = new ImageLabelSample(gs.session, gs.time);
    sample.imageSize = new BISize(width, height);
    sample.labels = Array(labelCount);

    for (var i = 0; i < labelCount; i++) {
        var label = new ImageLabel();
        var baseIndex = 4 + 7 * i;
        if (gs.values[baseIndex + 0] != null) label.class = gs.values[baseIndex + 0];
        label.id = gs.values[baseIndex + 1];
        if (gs.values[baseIndex + 2] > 0) label.distance = gs.values[baseIndex + 2];

        var left = gs.values[baseIndex + 3];
        var top = gs.values[baseIndex + 4];
        var right = gs.values[baseIndex + 5];
        var bottom = gs.values[baseIndex + 6];
        label.rect = new ImageLabelRect(left, top, right - left, bottom - top);

        sample.labels[i] = label;
    }

    return sample;
}

function convImageLabelSampleV2(gs) {
    if (gs.values.length < 8) return null;
    if (gs.values[0] == null || gs.values[0] != gs.channel) return null;
    if (gs.values[1] == null || gs.values[2] == null || gs.values[3] == null) return null;

    var width = gs.values[1];
    var height = gs.values[2];
    var labelCount = gs.values[3];
    if (gs.values.length != 8 + labelCount * 16) return null;

    var sample = new ImageLabelSample(gs.session, gs.time);
    sample.imageSize = new BISize(width, height);
    sample.labels = Array(labelCount);

    for (var i = 0; i < labelCount; i++) {
        var label = new ImageLabel();
        var baseIndex = 8 + 16 * i;
        if (gs.values[baseIndex + 0] != null) label.class = gs.values[baseIndex + 0];
        label.id = gs.values[baseIndex + 1];
        label.distance = gs.values[baseIndex + 2];

        var left = gs.values[baseIndex + 3];
        var top = gs.values[baseIndex + 4];
        var right = gs.values[baseIndex + 5];
        var bottom = gs.values[baseIndex + 6];
        label.rect = new ImageLabelRect(left, top, right - left, bottom - top);

        label.classConfidence = gs.values[baseIndex + 7];
        label.description = gs.values[baseIndex + 8];

        sample.labels[i] = label;
    }

    return sample;
}

// Supported protocols / 图像标签样本支持解析的协议
var imageLabelSampleProtocols = [
    "image-label-sample-v1",
    "image-label-sample-v2",
];

// Use this function to query sample at target time / 获取指定session指定时刻的图像标签样本
function getImageLabelSample(channel, session, time) {
    var pairV2 = biGetGeneralSamplePair('image-label-sample-v2', channel, session, time, 1);
    var pairV1 = biGetGeneralSamplePair('image-label-sample-v1', channel, session, time, 1);
    if (pairV2 != null) {
        return pairV2.weight1 > pairV2.weight2 ? convImageLabelSampleV2(pairV2.sample1) : convImageLabelSampleV2(pairV2.sample2);
    }
    else if (pairV1 != null) {
        return pairV1.weight1 > pairV1.weight2 ? convImageLabelSampleV1(pairV1.sample1) : convImageLabelSampleV1(pairV1.sample2);
    }
    else return null;
} 